package com.tbvtc.agriculturalcreditchainserver2025.utils.redis;

import com.tbvtc.agriculturalcreditchainserver2025.exception.FoodException;
import com.tbvtc.agriculturalcreditchainserver2025.utils.ResultCodeEnum;
import com.tbvtc.agriculturalcreditchainserver2025.vo.farmerVo.FoodReportVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import static com.tbvtc.agriculturalcreditchainserver2025.constant.RedisConstant.CACHE_NULL_TTL;


/**
 * redis客户端工具类
 */
@Slf4j
@Component
public class CacheClient {

     @Resource(name = "TredisTemplate")
     private RedisTemplate<String, List<FoodReportVo>> redisTemplate;

    private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);
   //注入redisTemplate


    /**
     *redis存入数据可设置过期时间
     * @param key
     * @param value
     * @param time
     * @param unit
     */
    public void set(String key, List<FoodReportVo> value, Long time, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, time, unit);
    }

    /**
     * (逻辑过期)
     * @param key
     * @param value
     * @param time
     * @param unit
     */
//    public void setWithLogicalExpire(String key, Object value, Long time, TimeUnit unit) {
//        // 设置逻辑过期
//        RedisData redisData = new RedisData();
//        redisData.setData(value);
//        redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));
//        // 写入Redis
//        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));
//    }

    /**
     *缓存穿透
     * @param keyPrefix
     * @param type
     * @param dbFallback
     * @param time
     * @param unit
     * @return
     * @param <ID>
     */
    public <ID>  List<FoodReportVo> queryWithPassThrough(
            String keyPrefix, ID foodName,
            Class<List> type, //类型
            Function<ID,  List<FoodReportVo>> dbFallback,//区块链查询方法
            Long time, TimeUnit unit){
        String  key = keyPrefix + foodName;
        // 1.从redis查询报告
        List<FoodReportVo> reportVos = redisTemplate.opsForValue().get(key);
        // 2.判断是否存在
        if (reportVos!=null) {
            // 3.存在，直接返回
            return  reportVos;
        }
        // 4.不存在，根据名字查询链
        try {
            List<FoodReportVo> r = dbFallback.apply(foodName);
            // 5.不存在，返回错误
            // 6.存在，写入redis
            this.set(key, r, time, unit);
            return r;
        } catch (Exception e) {
            // 将空值写入redis
            redisTemplate.opsForValue().set(key,Collections.emptyList() , CACHE_NULL_TTL, TimeUnit.MINUTES);
            // 返回错误信息
            throw new FoodException(ResultCodeEnum.FAILED_TO_CHAIN);
        }
    }




}
